package moon.excel.reader.impl;

import java.io.InputStream;
import java.util.Arrays;

import javax.activation.MimeType;

import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import moon.excel.ExcelWraperException;
import moon.excel.IObgainWorkbook;
import moon.excel.IRecordInterceptor;
import moon.excel.constants.ExcelConstants;
import moon.excel.reader.IExcelReader;
import moon.excel.util.ExcelUtil;

/***
 * 基于dom方式读取excel
 * 
 * @author Sunset
 *
 */
public class DomExcelReader implements IExcelReader, IObgainWorkbook {

	FormulaEvaluator eva = null;
	private Workbook wb;

	/**
	 * 初始化读取器
	 * 
	 * @param type
	 *            文件类型
	 * @param input
	 *            输入流
	 */
	public DomExcelReader(MimeType fileType, InputStream input) {
		try {
			if (ExcelConstants.MIMETYPE_XLS.match(fileType)) {
				wb = new HSSFWorkbook(input);
				eva = new HSSFFormulaEvaluator((HSSFWorkbook) wb);
			} else if (ExcelConstants.MIMETYPE_XLSX.match(fileType)) {
				wb = new XSSFWorkbook(input);
				eva = new XSSFFormulaEvaluator((XSSFWorkbook) wb);
			} else {
				throw new ExcelWraperException("创建excel失败,请检查文件格式。");
			}

		} catch (ExcelWraperException e) {
			throw e;
		} catch (Exception e) {
			e.printStackTrace();
			throw new ExcelWraperException("创建excel失败,请检查文件格式和内容。");
		}
	}

	@Override
	public void readSheet(Integer sheetIndex, int rowBeginIndex, int columnBeginIndex, int columnEndIndex, Class<?>[] classs, IRecordInterceptor<Object[]> interceptor) {
		Sheet sheet = wb.getSheetAt(sheetIndex);
		if (sheet == null) {
			throw new RuntimeException("sheet不存在");
		}
		int lastRow = sheet.getLastRowNum();
		for (int i = rowBeginIndex; i <= lastRow; i++) {
			Object[] os = readRow(sheetIndex, i, columnBeginIndex, columnEndIndex, classs);
			interceptor.handle(os, i + 1);
		}
	}

	@Override
	public void readSheet(Integer sheetIndex, int columnBeginIndex, int columnEndIndex, int[] rowIndexs, Class<?>[] classs, IRecordInterceptor<Object[]> interceptor) {
		for (int i : rowIndexs) {
			Object[] os = readRow(sheetIndex, i, columnBeginIndex, columnEndIndex, classs);
			interceptor.handle(os, i);
		}
	}

	/** */
	private Object getObjectValue(Cell cell) {
		Object r = "";
		if (cell != null) {
			int type = cell.getCellType();
			switch (type) {
			case Cell.CELL_TYPE_NUMERIC:
				double val = cell.getNumericCellValue();
				long temp = Math.round(val);
				if (val == temp) {
					r = temp;
				} else {
					r = val;
				}
				break;
			case Cell.CELL_TYPE_BOOLEAN:
				r = cell.getBooleanCellValue();
				break;
			case Cell.CELL_TYPE_FORMULA:
				r = getObjectValue(eva.evaluateInCell(cell));
				break;
			default:
				r = cell.getRichStringCellValue().getString();
				break;
			}
		}
		return r;
	}

	@Override
	public Object[] readRow(Integer sheetIndex, int rowIndex, int columnBeginIndex, int columnEndIndex, Class<?>[] classs) throws UnsupportedOperationException {
		if (sheetIndex < 0 || rowIndex < 0 || columnBeginIndex < 0 || columnEndIndex < 0 || columnBeginIndex >= columnEndIndex) {
			throw new RuntimeException("行列索引 必须大于等于0且列开始索引必须小于等于列结束索引");
		}
		Sheet sheet = wb.getSheetAt(sheetIndex);
		if (sheet == null) {
			throw new RuntimeException("sheet不存在");
		}
		Object[] os = new Object[columnEndIndex - columnBeginIndex + 1];
		Row row = sheet.getRow(rowIndex);
		if (row != null) {
			for (int i = 0; i < os.length; i++) {
				Cell cell = row.getCell(i + columnBeginIndex);
				os[i] = getObjectValue(cell);
				if (os[i] != null && classs != null && classs.length == os.length && classs[i] != null) {
					try {
						if (!classs[i].isAssignableFrom(os[i].getClass())) {
							os[i] = ExcelUtil.convert(os[i], classs[i]);
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		} else {
			os = new Object[columnEndIndex - columnBeginIndex + 1];
			Arrays.fill(os, "");
		}
		return os;
	}

	@Override
	public Workbook getWorkbook() {
		return wb;
	}

}
